/*
* 所谓递归下降，就是每一种type的token，都对应着它自己的解析方式
* 跟antlr相对应就是，g4规定了文法，按什么样的方式去解析
* 解析到了tokens，遍历tokens
* 根据不同类型的token，来解析，解析完了之后返回
*
*
* 需要拆分：
*   按简单的步骤，一步步来做，才行
*   比如先解析简单语法
*       number boolean string null 都是直接返回的
*       keyword [break, const, continue, if, else, while, for, function, return, this, var]
*               关键词的返回必须要带类型，因为它有特定的操作
*       variable 也是直接返回
*
* */

const visitLiteral = (tokens, begin) => {
    let i = begin
    const token = tokens[i]
    const {tokenValue, tokenType} = token
    // 同理 string，number，boolean，null都是这样处理的

    // token是number的时候，可能是只有number，比如 var a = 10
    // 还有可能是数字之后跟了表达式，比如 var a = 99 + 1
    // 那能不能说是：「var a = 」这个模式后面是跟的表达式呢？
    // 这个比较合理: var a = expression
    // 也就是遇到 var a 之后，就去解析下一个expression
    // 那expression有很多种形式啊： a * b, a * function(10)...
    // 所以在拿到当前token之后，再拿一下next元素, 根据下一个元素来做决定
    // log('number token:', tokenValue)
    if (i + 1 < tokens.length) {
        // log(`${tokenValue}后有表达式式`)
        const nextToken = tokens[i + 1]
        if ([Type.plus, Type.minus, Type.multiply, Type.divide,Type.greaterThan].includes(nextToken.tokenType)) {
            // // 下一个元素是二元操作符，那么再下一个元素也是一个expression
            //截取当前到到; 为止的所有expTokens
            let expTokens = []
            for (let j = i; j < tokens.length; j++) {
                if(tokens[j].tokenType === Type.semicolon){
                    break
                }
                expTokens.push(tokens[j])
            }
            return [parserExpToTree(expTokens), expTokens.length+1]
        } else {
            // 不是表达式。。再看吧
            // 不是2元表达式，则按一个数字处理
            // log('只有一个数字：', tokenValue)
            return [
                {
                    name: tokenType,
                    value: tokenValue
                },
                i - begin + 1, // 消耗了几个token
            ]
        }
    } else {
        // 只有一个数字
        // log('只有一个数字：', tokenValue)
        return [
            {
                name: tokenType,
                value: tokenValue
            },
            i - begin + 1, // 消耗了几个token
        ]
    }
}

const visitVar = (tokens, begin) => {
    let i = begin
    const varName = tokens[i + 1]
    // 跳过 = 号, 从i + 3开始
    const v = ufmi(tokens, i + 3)
    return [{
        name: 'var',
        identifier: varName.tokenValue,
        value: v[0]
    }, v[1] + 2]
}
const visitArray = (tokens, begin) =>{
    let elements = []
    let k = begin + 1
    while(k<tokens.length){
        if(tokens[k].tokenValue === ","){
            k += 1
        } else if(tokens[k].tokenValue === "]"){
            break
        }else {

            let element = ufmi(tokens, k)
            elements.push(element)
            k += element[1]
        }
    }
    return [
        {
            "type":"ArrayExpression",
            "elements": elements,
        },
        k - begin + 1  // 消耗了几个token
    ]
}
const visitObject = (tokens, begin) =>{

    let properties = []
    let k = begin + 1
    while(k<tokens.length){

        if(tokens[k].tokenValue === ":"){
            let key = tokens[k-1]
            let value = ufmi(tokens, k + 1)
            k += value[1]
            let property = {
                "type":"objectProperty",
                "key": key,
                "value":value
            }
            properties.push(property)

        } else if(tokens[k].tokenValue === "}"){
            // log("花括号结束")
            break
        }
        k += 1
    }

    return [
        {
            "type":"objectExpression",
            "propertires": properties,
        },
        k - begin + 1, // 消耗了几个token
    ]
}
const blockStatement = (tokens, begin) =>{
    const r = ufmi(tokens, begin)
    return [{
        type: "BlockStatement",
        propertires: r[0],
    }, r[1]]
}
const visitIf =  (tokens, begin) => {

    let ifStatement = {
        type:"IfStatement",
    }
    let k = begin + 2

    let elements = []
    while(k<tokens.length){
        if(tokens[k].tokenValue === ","){
            k += 1
        } else if(tokens[k].tokenValue === ")"){
            break
        }else {
            let element = ufmi(tokens, k)
            elements.push(element)
            k += element[1]
        }
    }
    ifStatement["condition"] = elements

    k += 2

    let ifBlock = blockStatement(tokens, k)
    k += ifBlock[1]
    ifStatement["ifBlock"] = ifBlock
    while (k < tokens.length){
        if(tokens[k].tokenValue === "else"){
            let elseBlock = blockStatement(tokens, k+2)
            k += elseBlock[1]
            ifStatement["elseBlock"] = elseBlock
        }
        k += 1
    }
    return [ifStatement, k - begin]

}
const visitFunction =  (tokens, begin) => {

    let functionStatement = {
        type:"FunctionExpression",
    }
    let k = begin + 2
    let elements = []
    while(k<tokens.length){
        if(tokens[k].tokenValue === ","){
            k += 1
        } else if(tokens[k].tokenValue === ")"){
            break
        }else {
            let element = ufmi(tokens, k)
            elements.push(element)
            k += element[1]
        }
    }


    functionStatement["params"] = elements

    k += 2

    let functionBlock = blockStatement(tokens, k)
    k += functionBlock[1]
    functionStatement["functionBlock"] = functionBlock

    return [functionStatement, k - begin]

}
const popNode = (sOption, sNode) =>{
    //sOption + +
    //sNode 1 2 3
    let node = {
        "name": 'binaryExpression',
        "operator":  sOption.pop(),
        "right": sNode.pop(),
        "left": sNode.pop(),
    }
    //如果没有运算符的情况直接输出
    if(sOption.length === 0){
        return node
    }else {
        sNode.push(node)
        return popNode(sOption, sNode)
    }

}

const parserExpToTree = (tokens) =>{
    let _options = {
        "+": 1,
        "*": 2,
        "-": 1,
        "/": 2,
    }
    let sOption = []
    let sNode = []
    let k = 0
    while (k < tokens.length){
        const t = tokens[k]
        const {tokenValue, tokenType}  = t
        if(tokenType === Type.number || tokenType === Type.string|| tokenType === Type.variable){
            let nextToken =  tokens[k + 1]
            if(nextToken && nextToken.tokenType === Type.parenthesesLeft){
                let node = {
                    "type":"FunctionUse",
                    "funtionName": tokens[k].tokenValue,
                }
                k += 2
                let elements = []
                while(k<tokens.length){
                    if(tokens[k].tokenValue === ","){
                        k += 1
                    } else if(tokens[k].tokenValue === ")"){
                        break
                    }else {
                        elements.push(tokens[k])
                        k += 1
                    }
                }


                node["params"] = elements
                sNode.push(node)
            }else {
                sNode.push(t)
            }
        }else if(Object.keys(_options).includes(tokenValue)){
            //如过是空直接push
            if(sOption.length === 0){
                sOption.push(t)
            }else {
                let top = sOption[sOption.length -1].tokenValue
                //遇到优先级比较低的先出栈
                if(_options[top] > _options[tokenValue]){

                    let node = {
                        "right": sNode.pop(),
                        "name": 'binaryExpression',
                        "operator":  sOption.pop(),
                        "left": sNode.pop(),
                    }
                    sNode.push(node)
                    sOption.push(t)
                    // log("sOption", sOption)
                    // log("sNode", JSON.stringify(sNode))
                }else {
                    //同级或者低的直接入栈
                    sOption.push(t)
                }
            }
        } else if(tokenValue === "("){
            sOption.push(t)
        }else if(tokenValue === ")"){
            while (sOption.length !== 0){
                let top = sOption[sOption.length - 1].tokenValue
                if(top === "("){
                    sOption.pop()
                    break
                }else {
                    let node = {
                        "right": sNode.pop(),
                        "name": 'binaryExpression',
                        "operator":  sOption.pop(),
                        "left": sNode.pop(),
                    }
                    sNode.push(node)
                }

            }

        }
        k += 1
    }



    return popNode(sOption, sNode)
}
const ufmi = (tokens, begin) => {
    let i = begin
    let body = []

    while (i < tokens.length) {
        const token = tokens[i]
        const {tokenValue, tokenType} = token
        // log('当前访问', tokenValue, tokenType)
        if (tokenType === Type.keyword) {

            if (tokenValue === 'var') {
                const r = visitVar(tokens, i)
                i += r[1]
                body.push(r[0])
            } else if (tokenValue === 'if') {
                let vIf = visitIf(tokens, i)
                body.push(vIf[0])
                i += vIf[1]
            }
            else if (tokenValue === 'function') {
                let v = visitFunction(tokens, i)
                body.push(v[0])
                i += v[1]
                // log("拿到function了")
            }
        }else if (tokenValue === ")") {
            return  [body, i - begin]
        }else if (tokenValue === "}") {
            return  [body, i - begin]
        }else if ([Type.number, Type.string,Type.variable].includes(tokenType)) {
            return visitLiteral(tokens, i)
        }else if (Type.bracketLeft === tokenType) {
                let arr = visitArray(tokens, i)
                i += arr[1]
                return arr
        } else if (Type.curlyLeft === tokenType) {
                let obj = visitObject(tokens, i)
                i += obj[1]
            return obj
        }
        i += 1
        // log('加1的body', body, i)
    }
    //上边多加了一个1
    return [body, i - begin]
}

const test1 = () => {
    const code = `var a = 99`
    // const tl = new TokenList(code)
    // log(tl.tokenList)
    log("源码：", code)
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '99', tokenType: Type.number},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}

const test2 = () => {
    const code = `var a = 99 + 1`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 99, tokenType: Type.number},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 1, tokenType: Type.number},

        // {tokenValue: 'var', tokenType: Type.keyword},
        // {tokenValue: 'b', tokenType: Type.variable},
        // {tokenValue: '=', tokenType: Type.assign},
        // {tokenValue: 'a', tokenType: Type.variable},
        // {tokenValue: '+', tokenType: Type.plus},
        // {tokenValue: 1, tokenType: Type.number},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}

const test3 = () => {
    const code = `var a = "hello"`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: "hello", tokenType: Type.string},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}

const test4 = () => {
    // 对象测试
    const code = `var a = {
        test: 123,
    }`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: "{", tokenType: Type.curlyLeft},
        {tokenValue: "test", tokenType: Type.variable},
        {tokenValue: ":", tokenType: Type.colon},
        {tokenValue: 123, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},
    ]
    /*
    预期的结果是:
    {
        identifier: 'a',
        name: 'var',
        value: {
            name: 'object',
            objectProperties: [
                {
                    key: "value",
                    value: 123,
                },
                {
                    key: "test",
                    value: 99,
                }
            ]
        }
    }
    * */

    const result = ufmi(tokenList, 0)
    log('result:', result)
}

const test5 = () => {
    const code = `var a = 1 + 2 + 3`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)
}

const test6 = () => {
    const code = `var o = {
        test: 123,
    }`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'o', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: "test", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 123, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},
        {tokenValue: "}", tokenType: Type.curlyRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
    /*
    预期的结果是:
    {
        identifier: 'o',
        name: 'var',
        value: {
            name: 'object',
            objectProperties: [
                {
                    key: "value",
                    value: 123,
                },
            ]
        }
    }
    * */
}
const test7 = () => {
    const code = `var o = {
        test: 123,
        hello: 999
    }`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'o', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "test", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 123, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "hello", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 999, tokenType: Type.number},

        {tokenValue: "}", tokenType: Type.curlyRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test8 = () => {
    const code = `var person = {
    firstName:"John",
    lastName:"Doe",
    age:50,
    eyeColor:"blue"
}`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'person', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "firstName", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: "John", tokenType: Type.string},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "lastName", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: "Doe", tokenType: Type.string},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "age", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 50, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "eyeColor", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: "blue", tokenType: Type.string},

        {tokenValue: "}", tokenType: Type.curlyRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test9 = () => {
    const code = `var o = {
        test: 1 + 2,
        hello: 999
    }`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'o', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "test", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "hello", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "}", tokenType: Type.curlyRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test10 = () => {
    const code = `var o = {
        a : 1, 
        hello: { 
                b : 2 
                }
    }`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'o', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "a", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "hello", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: '{', tokenType: Type.curlyLeft},


        {tokenValue: "b", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},

        {tokenValue: "}", tokenType: Type.curlyRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}

const test11 = () => {
    const code = `var a = [1, 2, 3]`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '[', tokenType: Type.bracketLeft},

        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},


        {tokenValue: 3, tokenType: Type.number},
        // {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "]", tokenType: Type.bracketRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test12 = () => {
    const code = `var a = [1, [ 2 ], 3]`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '[', tokenType: Type.bracketLeft},

        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: '[', tokenType: Type.bracketLeft},
        {tokenValue: 2, tokenType: Type.number},
        // {tokenValue: ",", tokenType: Type.comma},
        {tokenValue: "]", tokenType: Type.bracketRight},
        {tokenValue: ",", tokenType: Type.comma},


        {tokenValue: 3, tokenType: Type.number},
        // {tokenValue: ",", tokenType: Type.comma},

        // {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "]", tokenType: Type.bracketRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test13 = () => {
    const code = `var a = [
        1, 
        {
            test: 'fep3',
        }, 
        3,
    ]`
    const tokenList = [
        {tokenValue: 'var', tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '[', tokenType: Type.bracketLeft},

        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "test", tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 'fep3', tokenType: Type.string},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "}", tokenType: Type.curlyRight},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ",", tokenType: Type.comma},

        {tokenValue: "]", tokenType: Type.bracketRight},
    ]
    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test14 = () => {
    const code = `
        if (2 > 1) {
            var a = 1
            var b = 2
        }
    `
    const tokenList = [
        {tokenValue: 'if', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '>', tokenType: Type.greaterThan},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ")", tokenType: Type.parenthesesRight},

        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 2, tokenType: Type.number},

        {tokenValue: "}", tokenType: Type.curlyRight},
    ]

    /*
        预期：
        {
            type: 'IfStatement',
            condition: {
                type: 'binaryExpression',
                operator: '>',
                left: 2,
                right: 1,
            },
            ifBlock: [
                {
                    type: 'variableDeclaration',
                    kind: 'var',
                    identity: 'a',
                    value: {
                        type: number,
                        value: 1
                    }
                }
            ]
        }
    * */

    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test15 = () => {
    const code = `
        if (2 > 1) {
            var a = 1
        } else {
            var b = 99
        }
    `
    const tokenList = [
        {tokenValue: 'if', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '>', tokenType: Type.greaterThan},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ")", tokenType: Type.parenthesesRight},

        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},

        {tokenValue: 'else', tokenType: Type.keyword},
        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 99, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},
    ]

    /*
        预期：
        {
            type: 'IfStatement',
            condition: {
                type: 'binaryExpression',
                operator: '>',
                left: 2,
                right: 1,
            },
            ifBlock: [
                {
                    type: 'variableDeclaration',
                    kind: 'var',
                    identity: 'a',
                    value: {
                        type: number,
                        value: 1
                    }
                }
            ],
            elseBlock: [
                 {
                    type: 'variableDeclaration',
                    kind: 'var',
                    identity: 'b',
                    value: {
                        type: number,
                        value: 99
                    }
                }
            ]
        }
    * */

    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test16 = () => {
    const code = `
        if (2 > 1) {
            var a = 1
        } else {
            var b = {
                test: 99
            }
        }
    `
    const tokenList = [
        {tokenValue: 'if', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '>', tokenType: Type.greaterThan},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ")", tokenType: Type.parenthesesRight},

        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},

        {tokenValue: 'else', tokenType: Type.keyword},
        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: 'test', tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 99, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},
        {tokenValue: "}", tokenType: Type.curlyRight},
    ]

    /*
        预期：
        {
            type: 'IfStatement',
            condition: {
                type: 'binaryExpression',
                operator: '>',
                left: 2,
                right: 1,
            },
            ifBlock: [
                {
                    type: 'variableDeclaration',
                    kind: 'var',
                    identity: 'a',
                    value: {
                        type: number,
                        value: 1
                    }
                }
            ],
            elseBlock: [
                 {
                    type: 'variableDeclaration',
                    kind: 'var',
                    identity: 'b',
                    value: {
                        type: number,
                        value: 99
                    }
                }
            ]
        }
    * */

    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test17 = () => {
    const code = `
        var x = 199
        if (2 > 1) {
            var a = 1
        } else {
            var b = {
                test: 99
            }
        }
    `
    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'x', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 199, tokenType: Type.number},

        {tokenValue: 'if', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '>', tokenType: Type.greaterThan},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ")", tokenType: Type.parenthesesRight},

        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},

        {tokenValue: 'else', tokenType: Type.keyword},
        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: 'test', tokenType: Type.variable},
        {tokenValue: ':', tokenType: Type.colon},
        {tokenValue: 99, tokenType: Type.number},
        {tokenValue: "}", tokenType: Type.curlyRight},
        {tokenValue: "}", tokenType: Type.curlyRight},
    ]

    /*
        预期：
        {
            type: 'IfStatement',
            condition: {
                type: 'binaryExpression',
                operator: '>',
                left: 2,
                right: 1,
            },
            ifBlock: [
                {
                    type: 'variableDeclaration',
                    kind: 'var',
                    identity: 'a',
                    value: {
                        type: number,
                        value: 1
                    }
                }
            ],
            elseBlock: [
                 {
                    type: 'variableDeclaration',
                    kind: 'var',
                    identity: 'b',
                    value: {
                        type: number,
                        value: 99
                    }
                }
            ]
        }
    * */
    log("源码：",code)
    const result = ufmi(tokenList, 0)
    log('result:', result)
}
const test19 = () => {
    const code = `
        var f = function(a, b) {
        }
    `

    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'f', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 'function', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: ',', tokenType: Type.comma},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '{', tokenType: Type.curlyLeft},
        {tokenValue: '}', tokenType: Type.curlyRight},
    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)
    /*
        预期:
            [
                type: "VariableDeclaration",
                kind: "var",
                identifier: "f",
                value: {
                    type: "FunctionExpression",
                    params: [
                        {
                            type: "Identifier",
                            name: "a",
                        },
                        {
                            type: "Identifier",
                            name: "b",
                        },
                    ],
                    functionBlock: {
                        type: "BlockStatement",
                        properties: [
                        ]
                    }
                }
            ]

    * */
}

const test20 = () => {
    const code = `
        var f = function(a, b) {
            var x = 1
            var y = 99
        }
    `

    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'f', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 'function', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: ',', tokenType: Type.comma},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'x', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'y', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 99, tokenType: Type.number},

        {tokenValue: '}', tokenType: Type.curlyRight},
    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)
    /*
        预期:
            [
                type: "VariableDeclaration",
                kind: "var",
                identifier: "f",
                value: {
                    type: "FunctionExpression",
                    params: [
                        {
                            type: "Identifier",
                            name: "a",
                        },
                        {
                            type: "Identifier",
                            name: "b",
                        },
                    ],
                    functionBlock: {
                        type: "BlockStatement",
                        properties: [
                            {
                                type: "VariableDeclaration",
                                kind: "var",
                                identifier: "x",
                                value: 1,
                            },
                            {
                                type: "VariableDeclaration",
                                kind: "var",
                                identifier: "y",
                                value: 99,
                            },
                        ]
                    }
                }
            ]

    * */
}


const test21 = () => {
    const code = `
        var a = 1 + 2 + 3
    `

    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},

    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)

}
const test22 = () => {
    const code = `
        var a = 1 * (2 + 3) 
    `
    log("源码：", code)
    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: '*', tokenType: Type.multiply},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: ';', tokenType: Type.semicolon},


    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)

}

const test23 = () => {
    const code = `
        var a = 1 * (2 + 3) + 4 / 5
    `
    log("源码：", code)
    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: '*', tokenType: Type.multiply},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 4, tokenType: Type.number},
        {tokenValue: '/', tokenType: Type.divide},
        {tokenValue: 5, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},


    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)

}

const test24 = () => {
    const code = `
        var a = 1 * (2 + 3) + 4 / 5
        var f = function(a, b) {
            var x = 2 + 3
            var y = 99
        }
    `
    log("源码：", code)
    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: '*', tokenType: Type.multiply},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 4, tokenType: Type.number},
        {tokenValue: '/', tokenType: Type.divide},
        {tokenValue: 5, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'f', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 'function', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: ',', tokenType: Type.comma},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'x', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'y', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 99, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},

        {tokenValue: '}', tokenType: Type.curlyRight},


    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)

}

const test25 = () => {
    const code = `
        var a = 1 * (2 + 3) + 4 / 5
        var f = function(a, b) {
            var x = 2 + 3
            var y = (99+1)/3 
        }
    `
    log("源码：", code)
    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: '*', tokenType: Type.multiply},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 4, tokenType: Type.number},
        {tokenValue: '/', tokenType: Type.divide},
        {tokenValue: 5, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'f', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 'function', tokenType: Type.keyword},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: ',', tokenType: Type.comma},
        {tokenValue: 'b', tokenType: Type.variable},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '{', tokenType: Type.curlyLeft},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'x', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},

        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'y', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},

        {tokenValue: 99, tokenType: Type.number},
        {tokenValue: "+", tokenType: Type.plus},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: '/', tokenType: Type.divide},
        {tokenValue: 3, tokenType: Type.number},

        {tokenValue: ';', tokenType: Type.semicolon},

        {tokenValue: '}', tokenType: Type.curlyRight},


    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)

}
const test26 = () => {
    const code = `
        var a = b + 1
    `

    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: "b", tokenType: Type.variable},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: 1, tokenType: Type.number},
        {tokenValue: ';', tokenType: Type.semicolon},

    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)

}
const test27 = () => {
    const code = `
        var a = b + sum(1, 2)
    `
    log("源码：", code)
    const tokenList = [
        {tokenValue: "var", tokenType: Type.keyword},
        {tokenValue: 'a', tokenType: Type.variable},
        {tokenValue: '=', tokenType: Type.assign},
        {tokenValue: "b", tokenType: Type.variable},
        {tokenValue: '+', tokenType: Type.plus},
        {tokenValue: "sum", tokenType: Type.variable},
        {tokenValue: '(', tokenType: Type.parenthesesLeft},
        {tokenValue: 2, tokenType: Type.number},
        {tokenValue: ',', tokenType: Type.colon},
        {tokenValue: 3, tokenType: Type.number},
        {tokenValue: ')', tokenType: Type.parenthesesRight},
        {tokenValue: ';', tokenType: Type.semicolon},

    ]

    const result = ufmi(tokenList, 0)
    log('result:', result)

}
const test = () => {
    // test1()
    // test2()
    // test3()
    // test5()
    // test17()
    // test20()
    test27()

}

const _main = () => {
    log('parser')
    test()
}

_main()

